/** @jsxImportSource @emotion/react */
import * as React from "react";
import {
    Text, Toolbar, useTheme, Button, Container, IconCloud, InputLine, Input, Select, useToast, useMMenuBarOcup,
} from "customize-easy-ui-component";
import food from "../images/food.svg";
import { Layout } from "./Layout";
import { Link as RouterLink } from "@/routing/Link";
import {usePreloadedQuery, useQueryLoader} from "react-relay/hooks";
import {DeviceMaintQuery$data} from "./__generated__/DeviceMaintQuery.graphql";
import useSyncEqpMutation from "./useSyncEqpMutation";
import {useRef} from "react";
import {IconCircle} from "customize-easy-ui-component/esm/Icons/icons/IconCircle";
import {AloneContainer} from "@/comp/AloneContainer";

/**分片作业比较麻烦点：需要确认，启动验证码除了初始密码，确认时刻需要输入"sure"口令，而且JsliceMang表需要修改offset limit total；
 * 应该一直运行到“无法前进offset”才算完结。offset最初=0; total=目标分片发起对象表的最大记录个数；limit根据时间调整，每个分片时间不超过1分钟。
 * 【异常】分片作业后端：报错暂停:116901；场合：网络失败, 要手动修改： offs应当后退一个limt才能确保数据完整。
 * 【注意】步骤操作前提：并非孤立的，隐藏约束和执行顺序。【甚至】人工修订数据。
 * */
//比较特殊：直接用对象,提取对象Key，而不通常是用数组[,];
export const 设备同步作业={
    "AD":{ name: "01建Adminunit阶段(非分片)",
        desc: "建Adminunit更多选项",
        arg:{
            "Al": "1安上行政区划-过渡源头表",
            "cn": "2国家地区",
            "Pv": "3建1L省份表",
            "Ct": "4建地级市表",
            "qX": "5建区县级表",
            "Tp": "6-1建街道乡镇级别-预处理",
            "TW": "6-2建街道乡镇级别",
            "Ex": "7刚生成的乡镇表例外处理",
            "dY": "8为乡镇级Town生成管理单元",
            "GJp": "9-1为省市行政区域生成管理单元",
            "GJc": "9-2为县区级的区域生成管理单元",
            "Lb": "10安上旧检验楼盘-过渡表",
        }
    },
    "AU":{ name: "02安旧平台表等(分片)",
        desc: "最新旧平台所有单位",
        arg:{
            "Jy": "1安上旧检验单位全表",
            "Pu": "2安上管道单元列表对接表",
        }
    },
    "Su":{ name: "03更新Unit表(分片)",
        desc: "更新Unit表更多选项",
        arg:{
            "Jy": "1旧检验单位整表导Unit",
        }
    },
    "RL":{ name: "04接口对接单位(分片)",
        desc: "接口对接更多选项",
        arg:{
            "Bm": "1安上接口对接表使用单位的部门",
            "Sd": "2安上对接表使用单位的分支机构",
            "vL": "3生成楼盘对应的Village",
            "Of": "4依照HR部门生成Office",
        }
    },
    "JU":{ name: "05特检院部门科室..等(非分片)",
        desc: "部门分支..等更多选项",
        arg:{
            "DP": "1安上旧检验平台的HR部门-tree",
            "Pz": "2依照HR部门生成导Division",
            "Ls": "临时#:Isp的关联Eqp没有了，需清理",
        }
    },
    "VF":{ name: "06部门楼盘...(分片)",
        desc: "部门楼盘...更多选项",
        arg:{
            "jD": "1从部门接口对接表导进Division",
            "jS": "2从分支机构接口对接导进Division",
        }
    },
    'AK':'07 快照所有设备码 (分片)',
    "TZ":{ name: "07 设备台账...(分片)",
        desc: "设备台账...更多选项",
        arg:{
            "Kg": "1 设备码快照后还得过滤备删",
        }
    },
    "OD":{ name: "08 设备同步并发多通道",
        desc: "单个设备同步，5分区各自验证完成与否",
        arg:{
            ".1": "(并行)第一分区同步1",
            ".2": "(并行)第二分区同步2",
            ".3": "(并行)第三分区同步3",
            ".4": "(并行)第四分区同步4",
            ".5": "(并行)第五分区同步5",
        }
    },
    "Dm":{ name: "09 设备多通道",
        desc: "单个设备同步，5分区各自验证完成与否",
        arg:{
            ".1": "(并行)检查内容通道1",
            ".2": "(并行)检查内容通道2",
            ".3": "(并行)检查内容通道3",
            ".4": "(并行)检查内容通道4",
            ".5": "(并行)检查内容通道5",
        }
    },
    "Pi":{ name: "10 管道单元",
        desc: "单个设备同步，5分区各自验证完成与否",
        arg:{
            "EN.1": "2 接口表的管道单元转实体",
        }
    },
    "SI":{ name: "11 常规维护初始化ES (分片)",
        desc: "常规维护初始化ES...更多选项",
        arg:{
            "bC": "1 (预处理)对应的ES索引",
            "Ts": "2 定期检验任务生成",
            "ND": "3 年度检验任务生成",
        }
    },
    "DT":{ name: "12 常规维护Detail任务表 (分片)",
        desc: "常规维护Detail任务表...更多选项",
        arg:{
            "Oo": "1 (临时测试用)Isp-Detail关联转移",
        }
    },
    "SY":{ name: "13 索引同步任务(非分片)",
        desc: "关系数据库同步到ES搜索索引..等更多选项",
        arg:{
            "Ov": "1看索引同步任务是否结束",
            "ca": "2取消当前索引同步任务",
            "Is": "3同步Isp索引",
            "cP": "4同步Company索引",
            "pS": "5同步Person索引",
            "eQ": "6同步Eqp索引",
            "Pu": "7同步PipingUnit索引"
        }
    },
} as any;


const graphql = require("babel-plugin-relay/macro");
const DeviceMaintQuery = require('./__generated__/DeviceMaintQuery.graphql');

interface Props {
  prepared: {
  }
}
/**默认组件： 路由器入口；
 * */
export default function DeviceMaintWrapper(props: Props) {
  //第二个返回值loadQuery是回调(variables: VariablesOf<TQuery>, options?: UseQueryLoaderLoadQueryOptions) => void
  //第二个参数的类型必须完全一致！useQueryLoader与usePreloadedQuery保持一致类型？？

  const [queryReference, loadQuery] = useQueryLoader(
      DeviceMaintQuery  //GraphQLTaggedNode | PreloadableConcreteRequest<TQuery>,
      //PreloadedQuery<TQuery> | null,  provided by router
  );
  //第二个参数的： props.prepared.issuesQuery,
  //props.prepared父辈的已经做查询传递，还没给参数呢
  console.log("Test 目前render之后.New=",queryReference,"Old.parent=",props.prepared);
  //引入Relay思路大变：没有数据就没有页面展示，若需默认展示就必须提供缺省参数来准备好数据后才能执行页面显示代码。
    const theme = useTheme();
    //useState(默认值) ； 后面参数值仅仅在组件的装载时期有起作用，若再次路由RouterLink进入的，它不会依照该新默认值去修改show。useRef跳出Cpature Value带来的限制
    //采用RouterLink页内路由进入useState还保留旧的值，要修改就将会导致render两次；旧的值新的值各一次渲染。若采用URL刷新模式只有一次。
    //const [show, setShow] = React.useState(false);
    const [repId, setRepId] = React.useState('');
    const [repNo, setRepNo] = React.useState('');
    let filtercomp={ id:repId };

    //复检数据拷贝初检后再度修订的。最初的初检数据原封不动。复检rexm，正检data，结论及审核改定deduction｛也可部分照搬复检rexm正检data或映射转译｝。
    //原始记录录入模式复检正检，［正式报告来源项］只读的预览结论模式{动态生成结论}，(完毕提交)；
    //１原始记录　组件：不可改的不保存的［推断］结论项。　　　内容细化描述；复检正检数据切换的；结论项提示性质；　－－给检验操作人员录入。
    //２审核组件：回退或者往前固化结论项后保存给正式报告页面。　项目文本简化，数据需要保存给后端；－－正式报告手机可预览版，无下拉分区，不能编辑，－－核准管理人员审批。
    //３正式报告那个目录的打印页面。只读的，结论项也是读后端的；正式报告文书版本或可转保存其他如pdf类型文档，无下拉分区，全展示；－－大众用户查看。
    //审核但是不能修改检验数据模式，回退编制复检？或后台修正；校对转正式报告数据倒腾和推断合并结论项目，另外保存成了deduction，对表正式报告，报告排版美化。
    const [inp, setInp] = React.useState(null);
    //用<form >会影响到布局的，form也要css={}?。
    const { barHeight,bottomCss } = useMMenuBarOcup(false);

    return (
        <AloneContainer>
                 <div css={{
                    margin: 'auto',
                    background: "white"
                 }}
                 >
                    <form  method="post"
                           onSubmit={e =>{
                               e.preventDefault();
                               loadQuery({
                                    id: repNo,
                                   iwhere: {no: repNo}
                           }) } }>

                        <Text  variant="h5"　css={{ textAlign: 'center' }}>
                            <span>台账相关方面维护</span>
                        </Text>
                        <InputLine  label='用报告编号查' >
                            <Input  value={repNo}  placeholder="那一份报告？"
                                    onChange={e => setRepNo(e.currentTarget.value) } />
                        </InputLine>
                        <Button type="submit">搜索看有没有</Button>
                        <React.Suspense fallback="等下马上来...">
                            { queryReference && <DeviceMaint queryReference={queryReference} /> }
                        </React.Suspense>

                    </form>
                 </div>
                    <hr/>
                    <Text variant="h5" css={{ textAlign: 'center' }}>
                        业务端客户可以无密码登录进需申请。
                    </Text>
        </AloneContainer>
  );
}

//分片任务模式：不支持多个人一起抢作业去做。
const  PLEASE_INPUT="请再三确认分片偏移量已经不再继续移动";

interface DeviceMaintProps {
  queryReference: any;
}
/**作废”修改偏移量“按钮；
底下的‘修改偏移量’按钮借用了'发送同步请求'按钮的接口函数：复合接口模式。
从服务端取得的每个实体模型id都不允许相等的！Relay报错; $globalId = base64("$ObjectName:$ObjectPK").
* */
function DeviceMaint({ queryReference }:DeviceMaintProps)
{
  const data =usePreloadedQuery<typeof DeviceMaintQuery>(
      graphql`
          query DeviceMaintQuery(
              $after:String,$first:Int=10,$orderBy:String,$asc:Boolean=true,
              $iwhere:IspCommonInput
          ) {
              searchIsp(where: $iwhere,after:$after,first:$first,orderBy:$orderBy,asc:$asc)
              @connection(key: "Query_searchIsp") {
                  edges {
                      node {
                          id,entrust,dev{id,oid,cod},bus{id task{id,date}}
                      }
                  }
              }
          }
      `,
      queryReference,
  );
  //有必要？做个 ES搜索引擎 索引，就是给no报告号的搜索加速？？
    const { searchIsp: list }=data as DeviceMaintQuery$data;
    const isps = list && list.edges ? list.edges.map(edge => edge?.node) : [];
    const rep =isps && isps[0] && isps[0].dev;
  //  const { getReport: items }= (false)?  data! : {getReport:null};
  const theme = useTheme();
  //useState(默认值) ； 后面参数值仅仅在组件的装载时期有起作用，若再次路由RouterLink进入的，它不会依照该新默认值去修改show。useRef跳出Cpature Value带来的限制
  //采用RouterLink页内路由进入useState还保留旧的值，要修改就将会导致render两次；旧的值新的值各一次渲染。若采用URL刷新模式只有一次。
  //const [show, setShow] = React.useState(false);
  const [repId, setRepId] = React.useState('');
  const [repNo, setRepNo] = React.useState('');
  let filtercomp={ id:repId };
    const [offset, setOffset] = React.useState<number>(-1);
    const [type, setType] = React.useState<string|undefined>('SI');
  //复检数据拷贝初检后再度修订的。最初的初检数据原封不动。复检rexm，正检data，结论及审核改定deduction｛也可部分照搬复检rexm正检data或映射转译｝。
  //原始记录录入模式复检正检，［正式报告来源项］只读的预览结论模式{动态生成结论}，(完毕提交)；
  //１原始记录　组件：不可改的不保存的［推断］结论项。　　　内容细化描述；复检正检数据切换的；结论项提示性质；　－－给检验操作人员录入。
  //２审核组件：回退或者往前固化结论项后保存给正式报告页面。　项目文本简化，数据需要保存给后端；－－正式报告手机可预览版，无下拉分区，不能编辑，－－核准管理人员审批。
  //３正式报告那个目录的打印页面。只读的，结论项也是读后端的；正式报告文书版本或可转保存其他如pdf类型文档，无下拉分区，全展示；－－大众用户查看。
  //审核但是不能修改检验数据模式，回退编制复检？或后台修正；校对转正式报告数据倒腾和推断合并结论项目，另外保存成了deduction，对表正式报告，报告排版美化。
  // const [inp, setInp] = React.useState(null);
    const [doing, setDoing] = React.useState(false );
  //外部dat不能加到依赖，变成死循环! const  dat =items&&items.data&&JSON.parse(items.data);  这dat每次render都变了？
  //从后端返回的数据可能items已经被修改了
  // React.useEffect(() => {
  //   const  dat =rep&&rep.data&&JSON.parse(rep.data);
  //    dat && setInp(dat);
  // }, [rep]);
  //console.log("祖父OriginalRecord辈：捕获 ==inp=[",  inp,  "] rep=", rep );
    const {call:syncEqpFunc,doing:beDoing,result, called, reset}= useSyncEqpMutation();

    const subars=设备同步作业[type!];
    const [subarg, setSubarg] = React.useState<string|undefined>('');
    const [pasw, setPasw] = React.useState('');
    //useRef秘密武器啊
    const ackPasRef =useRef(null);
    const toast = useToast();
    const {auid: auidAck} =result??{};
        //syncEqpFunc( type!,subarg!, auidAck??pasw, offset);
    const sendCommand = React.useCallback(() => {
        if(auidAck && auidAck!==PLEASE_INPUT)
            syncEqpFunc( type!,subarg!, auidAck, offset);
        else syncEqpFunc( type!,subarg!, pasw, offset);
    }, [auidAck,pasw,offset, type, subarg,syncEqpFunc]);

    React.useEffect(() => {
        if(ackPasRef.current !== auidAck)
        {    //每次auidAck都会变动,作为发请求的依据
            ackPasRef.current =auidAck as any;
            if(auidAck && doing && !called){
                if(auidAck!==PLEASE_INPUT)
                    sendCommand();
                else{
                    setDoing(false);
                    toast({
                        title: "后端应答",
                        subtitle: auidAck,
                    });
                }
            }
            else if(doing && (!auidAck))
                setDoing(false);
        }
    }, [doing,called,ackPasRef, auidAck, sendCommand,toast]);

    React.useEffect( () => {
            if(!doing)  return;
            if(called)  reset();
            //如果真的是应答的才能这丫：开启时刻auidAck=null;
            if(ackPasRef.current && !auidAck)    setDoing(false);
    },[auidAck,doing,called,reset]);

    console.log("DeviceMaint页面2刷新result:", result ,"called=",called,"auidAck=",auidAck,"PKis=",ackPasRef.current,"doing=",doing);

  return (
          <div css={{
              margin: 'auto',
              background: "white"
            }}
          >
              <InputLine label={`后台作业类型选择：`}>
                  <Select inputSize="md"  value={ type || ''}
                          onChange={e => setType( e.currentTarget.value||undefined ) }
                  >
                    <option></option>
                   { Object.keys(设备同步作业).map((key) => (<option key={key} value={key}>
                       {typeof 设备同步作业[key] === 'object' ? 设备同步作业[key].name :设备同步作业[key] }
                        </option> )) }
                  </Select>
              </InputLine>
              { subars && typeof subars === 'object' &&
                  <InputLine label={`再选择${subars?.desc}:`}>
                      <Select inputSize="md"  value={ subarg || ''}
                              onChange={e => setSubarg( e.currentTarget.value||undefined ) }
                      >
                          <option></option>
                          { Object.keys(subars?.arg).map((key) => (<option key={key} value={key}>
                              {subars?.arg[key] }
                          </option> )) }
                      </Select>
                  </InputLine>
              }
              <InputLine  label='启动验证码' >
                  <Input  value={pasw ||''} type="password"
                          onChange={e => setPasw(e.currentTarget.value) } />
              </InputLine>
              <InputLine  label='分片模式偏移量(-1表示采用数据库)' >
                  <Input  value={offset || 0}   type={"number"}
                          onChange={e => setOffset( Number(e.currentTarget.value) )  } />
              </InputLine>
              <InputLine  label='当前完成量' >
                  <Input readOnly  value={`${result?.offs??''} / ${result?.totl??''}`}  />
              </InputLine>
              <Text variant="h5" css={{ textAlign: 'center' }}>
                  {result?.desc}
              </Text>
              <Button size="lg" intent="primary"  iconAfter={<IconCloud />}
                      disabled={beDoing}
                      onPress={ async () => {
                          setDoing(!doing);     //如果disabled不加上，有可能发送两次并发的请求!!。setDoing 到 doing=true的转换不是同步?!
                          !doing && syncEqpFunc( type!,subarg!, auidAck && auidAck!==PLEASE_INPUT? auidAck:pasw, offset);
                      }}
              >
               {'发送同步请求'}
              </Button>
              <Button size="lg" intent="primary"
                      disabled={doing}
                      onPress={ async () => {
                          syncEqpFunc( type!,"ModOffs:"+subarg, auidAck && auidAck!==PLEASE_INPUT? auidAck:pasw, offset);
                      }}
              >
                {'修改偏移量'}
              </Button>
              <Button size="lg" intent="primary"
                     onPress={ async () => {
                         setDoing(false);
                      }}
              >
                {'暂停运行'}
              </Button>
          </div>
  );
}

